package com.cltech.frame.utils;

import org.springframework.aop.framework.AdvisedSupport;
import org.springframework.aop.framework.AopProxy;
import org.springframework.aop.support.AopUtils;

import java.lang.reflect.Field;

/**
 * AopTargetUtils.
 * <p/>
 *
 * @author guanbo
 * @version 1.0.0.0
 */
public class AopTargetUtils {
        public AopTargetUtils() {
        }

        public static Object getTarget(Object proxy) throws Exception {
            if (!AopUtils.isAopProxy(proxy)) {
                return proxy;
            } else {
                return AopUtils.isJdkDynamicProxy(proxy) ? getJdkDynamicProxyTargetObject(proxy) : getCglibProxyTargetObject(proxy);
            }
        }

        private static Object getCglibProxyTargetObject(Object proxy) throws Exception {
            Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0");
            h.setAccessible(true);
            Object dynamicAdvisedInterceptor = h.get(proxy);
            Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised");
            advised.setAccessible(true);
            Object target = ((AdvisedSupport)advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget();
            return target;
        }

        private static Object getJdkDynamicProxyTargetObject(Object proxy) throws Exception {
            Field h = proxy.getClass().getSuperclass().getDeclaredField("h");
            h.setAccessible(true);
            AopProxy aopProxy = (AopProxy)h.get(proxy);
            Field advised = aopProxy.getClass().getDeclaredField("advised");
            advised.setAccessible(true);
            Object target = ((AdvisedSupport)advised.get(aopProxy)).getTargetSource().getTarget();
            return target;
        }
}
